import { CACHE_MANAGER, Inject, Injectable } from '@nestjs/common';
import { Cache, Store } from 'cache-manager'
import { RedisClient } from 'redis';
interface RedisStore extends Store {
  getClient? : {
      () : RedisClient
  }
}

@Injectable()
export class RedisService {
    public redisClient;
    constructor(
        @Inject(CACHE_MANAGER) private cacheManager: Cache
    ){
        const store:RedisStore = this.cacheManager.store
        this.redisClient = store.getClient()
    }

    set(...args : any[]) : Promise<boolean> {
        if(typeof args[1] != 'number') {
            args[1] = JSON.stringify(args[1]) 
        }
        return new Promise((resolve, reject) => {
            this.redisClient.set(...args, (err, result) => {
                if(!err &&  result === 'OK') {
                    resolve(true)
                }else {
                    resolve(false)
                }
            })
        })
    }

    hset(key:string, field, value) {
        return new Promise((resolve, reject) => {
            this.redisClient.hset(key, field, value, (err, result) => {
                if(!err && result) {
                    resolve(true)
                }else {
                    resolve(false)
                }
            })
        })
    }

    hget<T>(key:string, field) :Promise<T>{
        return new Promise((resolve, reject) => {
            this.redisClient.hget(key, field, (err, result) => {
                if(err) {
                    resolve(null)
                }else {
                    resolve(result)
                }
            })
        })
    }

    hmset(key:string, ...args : any[]) {
        return new Promise((resolve, reject) => {
            this.redisClient.hmset(key, ...args, (err, result) => {
                if(!err &&  result == 'OK') {
                    resolve(true)
                }else {
                    resolve(false)
                }
            })
        })
    }

    hgetall<T>(key:string) :Promise<T>{
        return new Promise((resolve, reject) => {
            this.redisClient.hgetall(key, (err, result) => {
                if(err) {
                    resolve(null)
                }else {
                    resolve(result)
                }
            })
        })
    }

    async call<T>(name:string, ...args:any[]) :Promise<T>{
        return new Promise((resolve, reject) => {
            this.redisClient[name](...args, (error, result) => {
                if(error) {
                    reject(error)
                }else {
                    resolve(result)
                }
            })
        })
    }

    async get<T>(key:string) :Promise<T>{
        let res = await this.cacheManager.get<T>(key)
        return typeof res === 'string' ? JSON.parse(res) : res
    }

    del(...args:string[]){
        return new Promise((resolve, reject) => {
            this.redisClient.del(...args, (err, res) => {
                if(err) {
                    reject(err)
                }else {
                    resolve(res)
                }
            })
        })
    }
}
